package com.xpec.c4.service.module;

import java.util.AbstractQueue;
import java.util.Collections;
import java.util.Iterator;
import java.util.Map;
import java.util.Queue;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * A Queue, that counting number of each element's Class info
 * @author zhangyuan 
 * @param <E> the type of elements held in this collection
 */
public class RecordedQueue<E> extends AbstractQueue<E> implements Queue<E>
{
	private Queue<E> queue = null;
	
	private Map<Class,AtomicInteger> countingMap = new ConcurrentHashMap<Class, AtomicInteger>();
	
	public Map<Class,AtomicInteger> getCountingMap()
	{
		return Collections.unmodifiableMap(countingMap);
	}
	
	public RecordedQueue(Queue<E> q)
	{
		queue = q;
	}	

	private void increaseClassCount(E e) 
	{
		AtomicInteger count = countingMap.get(e.getClass());
		
		if(count != null)
		{
			count.incrementAndGet();
		}
		else
		{
			countingMap.put(e.getClass(),new AtomicInteger(1));
		}		
	}
	
	private void decreaseClassCount(E e) 
	{
		AtomicInteger count = countingMap.get(e.getClass());
		
		if(count != null)
		{
			count.decrementAndGet();
		}
	}
	
	@Override
	public boolean offer(E e)
	{
		boolean re = queue.offer(e);
		
		if(true == re)
		{
			increaseClassCount(e);
		}
		
		return re;
	}

	@Override
	public E poll() 
	{
		E re = queue.poll();
		
		if(re != null)
		{
			decreaseClassCount(re);
		}
		
		return re;
	}

	@Override
	public E peek() 
	{
		return queue.peek();
	}

	@Override
	public Iterator<E> iterator() 
	{
	    return 
	    		new Iterator<E>() 
	    		{
	    			Iterator<? extends E> i = queue.iterator();

	    			public boolean hasNext() {return i.hasNext();}
	    			
	    			public E next() 	 {return i.next();}
	    			
	    			public void remove() 
	    			{
	    				E e = queue.remove();
	    				if(e != null)
	    				{
	    					decreaseClassCount(e);
	    				}
	    			}
	    		};
	}

	@Override
	public int size() 
	{
		return queue.size();
	}
	
	public boolean isEmpty()
	{
		return queue.isEmpty();
	}
}

